package org.hdl.anima.proxy;

import static com.google.common.base.Preconditions.checkArgument;

import java.util.concurrent.atomic.AtomicInteger;

import org.hdl.anima.AppConf;
import org.hdl.anima.Application;
import org.hdl.anima.message.IMessage;
import org.hdl.anima.transport.ChannelHandler;
import org.hdl.anima.transport.Codec;
import org.hdl.anima.transport.Constants;
import org.hdl.anima.transport.RemoteException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 
 * @author qiuhd
 * @since  2014年8月13日
 */
public class ServerProxyImpl implements ServerProxy {
	
	private static final Logger logger = LoggerFactory.getLogger(ServerProxyImpl.class);
	private final Application application;
	private ServerProxyConfig config;
	private final ChannelHandler channelHandler;
	private ExchangeClient[] proxyers;
	private final AtomicInteger proxyIndex = new AtomicInteger();
	private final AppConf conf ;
	
	public ServerProxyImpl(Application app,ServerProxyConfig  config) {
		checkArgument(app != null, "app == null!");
		checkArgument(config != null, "config == null!");
		this.application = app;
		this.config = config;
		conf = new AppConf(application.getAppConf());
		initAppConf(config);
		channelHandler = new ServerProxyHanlder(application,this);
		proxyers = new ExchangeClient[config.getConnects()];
	}
	
	
	private void initAppConf(ServerProxyConfig config) {
		this.conf.set(Constants.RECONNECT_KEY, config.getReconnect());
		this.conf.setBoolean(Constants.SEND_RECONNECT_KEY, config.isSendReconnect());
	}
	
	@Override
	public void setApplication(Application application) {
		checkArgument(application != null,"application is null!");
	}

	@Override
	public String getId() {
		return this.config.getId();
	}
	
	@Override
	public void start() throws RemoteException{
		for (int i= 0 ;i < config.getConnects();i++) {
			Codec codec = new ServerProxyCodec(application);
			ExchangeClient proxy =  new ExchangeClient(this, channelHandler, codec);
			proxyers[i] = proxy;
		}
	}

	@Override
	public void stop() {
		for (ExchangeClient proxy : proxyers) {
			proxy.close();
		}
		proxyers = null;
	}

	@Override
	public void send(int rid, IMessage msg) {
		checkArgument(msg != null,"message == null");
		try {
			nextProxy().send(rid, msg);
		} catch (RemoteException e) {
			logger.error("Failed to send messaga to proxy,Receiver id :{},Message id :{}",rid,msg.getId(),e);
		}catch (Exception e) {
			logger.error("Failed to send messaga to proxy,Receiver id :{},Message id :{}",rid,msg.getId(),e);
		}
	}

	@Override
	public void send(int identity, byte[] msg) throws RemoteException {
		checkArgument(msg != null,"msg == null");
		nextProxy().send(identity, msg);
	}
	
	@Override
	public void send(IMessage message) throws RemoteException {
		checkArgument(message != null,"message == null");
		try {
			nextProxy().send(message);
		} catch (RemoteException e) {
			logger.error("Failed to send messaga to proxy,Message id :{}",message.getId(),e);
		}catch (Exception e) {
			logger.error("Failed to send messaga to proxy,Message id :{}",message.getId(),e);
		}
	}

	private ExchangeClient nextProxy() {
	    return proxyers[Math.abs(proxyIndex.getAndIncrement() % proxyers.length)];
	}

	@Override
	public boolean isAvailable() {
		for (ExchangeClient proxy : proxyers) {
			if (proxy.isConnected())
				return true;
		}
		return false;
	}

	@Override
	public ServerProxyConfig getConifg() {
		return this.config;
	}

	@Override
	public Application getApplication() {
		return this.application;
	}

	@Override
	public AppConf getAppConf() {
		return this.conf;
	}
}

